package edu.w106.platform.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.zip.GZIPInputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.DefaultHttpClient;

public abstract class HttpClientUtils {
    private static final long serialVersionUID = -632871754475793049L;

    private final Log log = LogFactory.getLog(HttpClientUtils.class);

    protected final String DEFAULT_CHARSET = "UTF-8";

    protected Response sendRequest(HttpRequestBase request) throws IOException {
        Response httpresp = new Response(request.getURI().toString());

        request.setHeader("Accept-Encoding", "gzip, deflate");
        request.setHeader(
                "User-Agent",
                "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)");
        HttpClient httpClient = null;
        try {
            httpClient = new DefaultHttpClient();
            HttpResponse response = httpClient.execute(request);
            HttpEntity entity = response.getEntity();

            Header[] allheaders = response.getAllHeaders();
            for (int i = 0; allheaders != null && i < allheaders.length; i++) {
                httpresp.addHead(allheaders[i].getName(), allheaders[i].getValue());
            }
            Header encodeHeader = response.getLastHeader("Content-Encoding");
            String charset = getCharset(response.getLastHeader("Content-Type"));
            httpresp.setCharset(charset);
            int status = response.getStatusLine().getStatusCode();
            httpresp.setStatus(status);
            if (status == 200) {
                // gzip压缩模式返回的数据包
                if (isZipResponse(encodeHeader)) {
                    httpresp.setResponse(getGzippedData(entity, charset));
                } else {// 未压缩模式
                    httpresp.setResponse(getUnGzippedData(entity, charset));
                }
            } else {
                httpresp.setResponse("");
            }
            return httpresp;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            httpresp.setResponse(e.getMessage());
            return httpresp;
        } finally {
            closeHttpConnection(httpClient);
        }
    }

    private boolean isZipResponse(Header encodeHeader) {
        return encodeHeader != null && encodeHeader.getValue().toLowerCase().indexOf("gzip") > -1;
    }

    /**
     * 从http头中获取字符编码.
     * @param charset
     * @return
     */
    private String getCharset(Header charset) {
        if (charset == null) {
            return DEFAULT_CHARSET;
        }
        String charsetstr = charset.getValue();
        if (charsetstr.indexOf("charset") < -0) {
            return DEFAULT_CHARSET;
        }
        String[] strs = charsetstr.split("; ");
        for (String str : strs) {
            if (str.startsWith("charset")) {
                return str.split("=")[1].trim();
            }
        }
        return DEFAULT_CHARSET;
    }

    /**
     * 获取未压缩数据.
     * 
     * @param entity HttpClient的HttpEntry对象
     * @return 响应信息
     * @throws Exception 异常
     */
    private String getUnGzippedData(HttpEntity entity, String charset) throws IOException {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(entity.getContent(), charset));
            String line = null;
            StringBuffer sb = new StringBuffer();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            return sb.toString();
        } catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        } finally {
            closeIOResource(br);
        }
    }

    /**
     * 获取压缩数据.
     * 
     * @param entity HttpClient的HttpEntry对象
     * @return 响应信息
     * @throws Exception 异常
     */
    private String getGzippedData(HttpEntity entity, String charset) throws Exception {
        BufferedReader br = null;
        GZIPInputStream gzin = null;
        InputStreamReader isr = null;

        try {
            gzin = new GZIPInputStream(entity.getContent());
            isr = new InputStreamReader(gzin, charset);
            br = new BufferedReader(isr);
            StringBuffer sb = new StringBuffer();
            String tempbf;
            while ((tempbf = br.readLine()) != null) {
                sb.append(tempbf);
                sb.append("\r\n");
            }
            return sb.toString();
        } catch (Exception e) {
            throw e;
        } finally {
            closeIOResource(br);
            closeIOResource(isr);
            closeGzipResource(gzin);
        }
    }

    /**
     * 关闭Http连接.
     * 
     * @param httpClient
     *            HttpClient实例
     */
    private void closeHttpConnection(HttpClient httpClient) {
        try {
            httpClient.getConnectionManager().shutdown();
        } catch (Exception e) {
        }
    }

    /**
     * 关闭Gzip流.
     * 
     * @param gzin GZIP流
     */
    private void closeGzipResource(InputStream gzin) {
        try {
            if (gzin != null) {
                gzin.close();
            }
        } catch (Exception e) {
            gzin = null;
        }
    }

    /**
     * 关闭资源.
     * 
     * @param br
     *            输入流
     */
    private void closeIOResource(Reader br) {
        try {
            if (br != null) {
                br.close();
            }
        } catch (Exception e) {
        }
    }

}
